package com.sailing.xjpb.elasticsearch.repository;

import com.sailing.xjpb.common.exception.BusinessException;
import com.sailing.xjpb.common.exception.EsException;
import com.sailing.xjpb.elasticsearch.JestClientConfigurationPool;
import com.sailing.xjpb.elasticsearch.util.ESPage;
import com.sailing.xjpb.elasticsearch.util.EsUtil;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.*;
import io.searchbox.core.search.aggregation.TermsAggregation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.LinkedMap;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * es查询API
 *
 * @author luozy
 * createTime 2020/5/25
 */
@Slf4j
public class EsRepository {

    @Autowired
    private JestClientConfigurationPool jestClientConfigurationPool;

    /**
     * 返回查询结果为分页对象
     *
     * @param search: 查询条件
     * @param type:   Class<T> es查询返回List<T>
     * @return: com.sailing.es.util.ESPage
     * @author 罗志银
     * createDate 2020/08/10 12:31
     * editUser 姚伟 1、增加异常逻辑处理;2、减少不必要的maven依赖
     * editDate 2020/08/10 12:31
     */
    public <T> ESPage<T> queryForPage(Search search, Class<T> type) {
        if (type == null) {
            throw new EsException("查询结果类型不能为空！");
        }
        SearchResult searchResult = this.query(search);
        if (searchResult.getResponseCode() != 200) {
            if (searchResult.getResponseCode() == 404) {
                log.error("请确认ES地址或索引是否存在正确");
            } else {
                throw BusinessException.businessError(searchResult.getErrorMessage());
            }
        }
        // 取es数据
        List<T> tList = searchResult.getSourceAsObjectList(type, true);
        ESPage<T> esPage = new ESPage<>();
        esPage.setCount(searchResult.getTotal() == null ? 0 : searchResult.getTotal());
        esPage.setList(tList);
        return esPage;
    }

    /**
     * 查询结果为list
     *
     * @param search: 查询条件
     * @param type:   Class<T> es查询返回List<T>
     * @return: com.sailing.es.util.ESPage
     * @author 罗志银
     * createDate 2020/08/10 12:31
     * <p>
     * editUser 姚伟 1、增加异常逻辑处理;2、减少不必要的maven依赖
     * editDate 2020/08/10 12:31
     */
    public <T> List<T> queryForList(Search search, Class<T> type) {
        if (type == null) {
            throw new EsException("查询结果类型不能为空！");
        }
        SearchResult searchResult = this.query(search);
        // 取es数据
        return searchResult.getSourceAsObjectList(type, true);
    }

    /**
     * 查询es返回es原生的结果SearchResult
     *
     * @param search 查询对象
     * @return
     * @author YaoWei
     * createDate 2020年11月24日 上午10:18:14
     * editAuthor: YaoWei
     * editDate 2020年11月24日 上午10:18:14
     */
    public SearchResult query(Search search) {
        if (search == null) {
            throw new EsException("查询条件Search不能为空！");
        }
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            return jestClient.execute(search);
        } catch (Exception e) {
            throw new EsException("es查询失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }


    public <T> boolean save(String indexs, T data, String pattern) {
        indexs += "_" + new DateTime().toString(pattern);
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexs).refresh(true).defaultType(EsUtil.TYPE);
            Index index = new Index.Builder(data).build();
            bulk.addAction(index);
            JestResult jestResult = jestClient.execute(bulk.build());
            if (jestResult.isSucceeded()) {
                return true;
            } else {
                throw new EsException("es数据保存失败:" + jestResult.getErrorMessage());
            }
        } catch (EsException e) {
            throw e;
        } catch (Exception e) {
            throw new EsException("es数据保存失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }


    /**
     * 保存或更新ES数据
     *
     * @param indexs 索引名称
     * @param data   保存对象
     * @param id     主键 用于更新时使用，用实体中 不重复ID即可
     */
    public <T> boolean save(String indexs, T data, String id, String pattern) {
        indexs += "_" + new DateTime().toString(pattern);
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexs).refresh(true).defaultType(EsUtil.TYPE);
            Index index = new Index.Builder(data).id(id).build();
            bulk.addAction(index);
            JestResult jestResult = jestClient.execute(bulk.build());
            if (jestResult.isSucceeded()) {
                return true;
            } else {
                throw new EsException("es数据保存失败:" + jestResult.getErrorMessage());
            }
        } catch (EsException e) {
            throw e;
        } catch (Exception e) {
            throw new EsException("es数据保存失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }

    /**
     * 保存或更新ES数据
     *
     * @param indexs 索引名称
     * @param data   保存对象
     */
    public <T> boolean save(String indexs, T data, Date date, String pattern) {
        if (date == null) {
            date = new Date();
        }
        indexs += "_" + new DateTime(date).toString(pattern);
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexs).refresh(true).defaultType(EsUtil.TYPE);
            Index index = new Index.Builder(data).build();
            bulk.addAction(index);
            JestResult jestResult = jestClient.execute(bulk.build());
            if (jestResult.isSucceeded()) {
                return true;
            } else {
                throw new EsException("es数据保存失败:" + jestResult.getErrorMessage());
            }
        } catch (EsException e) {
            throw e;
        } catch (Exception e) {
            throw new EsException("es数据保存失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }


    public <T> boolean save(String indexs, List<T> dataList) {
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexs).refresh(true).defaultType(EsUtil.TYPE);
            for (T data : dataList) {
                Index index = new Index.Builder(data).build();
                bulk.addAction(index);
            }

            JestResult jestResult = jestClient.execute(bulk.build());
            if (jestResult.isSucceeded()) {
                return true;
            } else {
                throw new EsException("es数据保存失败:" + jestResult.getErrorMessage());
            }
        } catch (EsException e) {
            throw e;
        } catch (Exception e) {
            throw new EsException("es数据保存失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }

    public <T> boolean save(String indexs, List<T> dataList, String pattern) {
        indexs += "_" + new DateTime().toString(pattern);
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexs).refresh(true).defaultType(EsUtil.TYPE);
            for (T data : dataList) {
                Index index = new Index.Builder(data).build();
                bulk.addAction(index);
            }

            JestResult jestResult = jestClient.execute(bulk.build());
            if (jestResult.isSucceeded()) {
                return true;
            } else {
                throw new EsException("es数据保存失败:" + jestResult.getErrorMessage());
            }
        } catch (EsException e) {
            throw e;
        } catch (Exception e) {
            throw new EsException("es数据保存失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }

    public <T> boolean save(String indexs, List<T> dataList, Date date, String pattern) {
        if (date == null) {
            date = new Date();
        }
        indexs += "_" + new DateTime(date).toString(pattern);
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexs).refresh(true).defaultType(EsUtil.TYPE);
            for (T data : dataList) {
                Index index = new Index.Builder(data).build();
                bulk.addAction(index);
            }

            JestResult jestResult = jestClient.execute(bulk.build());
            if (jestResult.isSucceeded()) {
                return true;
            } else {
                throw new EsException("es数据保存失败:" + jestResult.getErrorMessage());
            }
        } catch (EsException e) {
            throw e;
        } catch (Exception e) {
            throw new EsException("es数据保存失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }


    public Double count(Count count) {
        return countResult(count).getCount();
    }

    private CountResult countResult(Count count) {
        if (count == null) {
            throw new EsException("统计条件Count不能为空！");
        }
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            return jestClient.execute(count);
        } catch (Exception e) {
            throw new EsException("es查询失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
    }


    public Map<String, Long> groupQuery(Search search, String alias) {
        Map<String, Long> map = new LinkedMap();
        SearchResult searchResult = null;
        JestClient jestClient = null;
        try {
            jestClient = jestClientConfigurationPool.getConnection();
            searchResult = jestClient.execute(search);
            //结果处理
            TermsAggregation termsAggregation = searchResult.getAggregations().getTermsAggregation(alias);
            for (TermsAggregation.Entry entry : termsAggregation.getBuckets()) {
                map.put(entry.getKey(), entry.getCount());
            }
        } catch (Exception e) {
            throw new EsException("es查询失败！", e);
        } finally {
            jestClientConfigurationPool.close(jestClient);
        }
        return map;
    }

}
